package com.bxl.netty.rpc.client.proxy;




import com.bxl.netty.rpc.client.RpcClientAgent;
import com.bxl.netty.rpc.client.common.register.CallBackRegister;
import com.bxl.netty.rpc.common.builder.MsgBuilder;
import com.bxl.netty.rpc.common.future.CompletableFuture;
import com.bxl.netty.rpc.common.message.PackageMsg;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 
 */

public class RpcProxy {
    public static <T> T proxyGet(final Class<T> interfaceInfo) {
        ClassLoader loader = interfaceInfo.getClassLoader();
        Class<?>[] methodInfo = {interfaceInfo};
        return (T) Proxy.newProxyInstance(loader, methodInfo, new MyInvocationHandler(interfaceInfo));
    }


    private static class MyInvocationHandler implements InvocationHandler {
        Class interfaceInfo = null;

        private int tryNum = 2;

        public MyInvocationHandler(Class interfaceInfo) {
            this.interfaceInfo = interfaceInfo;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            boolean isTry = true;
            int index = 0;
            Object rtn = null;
            PackageMsg packageMsg = null;
            while (isTry && index < tryNum) {
                try {
                    String name = interfaceInfo.getName();
                    String methodName = method.getName();
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    packageMsg = MsgBuilder.createMsg(name, methodName, args, parameterTypes);
                    //可以获取客户端，然后实现同一客户端的重试
                    CompletableFuture cf = RpcClientAgent.sendMsg(packageMsg);
                    rtn = cf.get();
                    isTry = false;
                } catch (Exception e) {
                    //避免内存泄露
                    CallBackRegister.removeCB(packageMsg.getHeader().getRequestID());
                    index++;
                }
            }
            
            if(index >= tryNum){
                throw new Exception("接口调用失败");
            }
            return rtn;
        }
    }
}

